package edu.maping.easy.model;

import java.util.ArrayList;
import java.util.List;

import processing.core.PApplet;
import processing.xml.XMLElement;

public class PolygonThing extends Thing {

	public ArrayList<Point> vertex = new ArrayList<Point>();

	public PolygonThing() {
		super();
	}

	public ArrayList<Point> getVertex() {
		return vertex;
	}

	public Point getPoint(int x, int y) {
		Point point = null;

		for (Point v : vertex) {
			boolean ok = v.isThisPoint(x, y);
			if (ok) {
				point = v;
				break;
			}
		}

		return point;
	}
	
	public void addPoint(Point point) {

		if (vertex.size() == 0) {
			vertex.add(point);
			point.first = true;
			vertex.add(vertex.size() - 1, point);
			this.setXY(point.x, point.y);
		} else {
			vertex.add(vertex.size() - 1, point);
		}
	}

	public void removePoint(Point point) {

		int index = vertex.indexOf(point);
		if (index == 0) {

		} else {
			vertex.remove(point);
		}

	}

	public void draw(PApplet applet) {
		
		if (vertex.isEmpty())
			return;

		applet.beginShape();

		Point pLast = vertex.get(0);
		applet.vertex(pLast.x, pLast.y);
		for (int i = 1; i < vertex.size(); i++) {
			Point p = vertex.get(i);
			applet.vertex(p.x, p.y);
			pLast = p;
		}
		applet.endShape();
	}

	public void editDraw(PApplet applet) {

		if (vertex.isEmpty())
			return;
		
		applet.noFill();

//		applet.stroke(0, 255, 0);
		applet.strokeWeight(1);
		Point pLast = vertex.get(0);
		applet.ellipse(pLast.x, pLast.y, 25, 25);
		for (int i = 1; i < vertex.size(); i++) {
			Point p = vertex.get(i);
			applet.ellipse(p.x, p.y, 25, 25);
			applet.line(pLast.x, pLast.y, p.x, p.y);
			pLast = p;
		}
	}

	public void moveXY(int x, int y) {
		// No actualizo el primero, porque es la misma instancia que el último
		this.move(x, y);
		for (int i = 1; i < vertex.size(); i++) {
			vertex.get(i).move(x, y);
		}
		refresh();
	}

	public boolean contains(Point p0) {
		return contains(p0, vertex);
	}

	protected boolean contains(Point p0, List<Point> vertices) {

		int x = p0.getX();
		int y = p0.getY();

		int npoints = vertices.size();
		if (npoints <= 2) {
			return false;
		}
		int hits = 0;

		Point last = vertices.get(vertices.size() - 1);
		int lastx = last.getX();// xpoints[npoints - 1];
		int lasty = last.getY();// ypoints[npoints - 1];
		int curx, cury;

		// Walk the edges of the polygon
		for (int i = 1; i < npoints; lastx = curx, lasty = cury, i++) {

			Point point = vertices.get(i);

			curx = point.getX();// xpoints[i];
			cury = point.getY();// ypoints[i];

			if (cury == lasty) {
				continue;
			}

			int leftx;
			if (curx < lastx) {
				if (x >= lastx) {
					continue;
				}
				leftx = curx;
			} else {
				if (x >= curx) {
					continue;
				}
				leftx = lastx;
			}

			double test1, test2;
			if (cury < lasty) {
				if (y < cury || y >= lasty) {
					continue;
				}
				if (x < leftx) {
					hits++;
					continue;
				}
				test1 = x - curx;
				test2 = y - cury;
			} else {
				if (y < lasty || y >= cury) {
					continue;
				}
				if (x < leftx) {
					hits++;
					continue;
				}
				test1 = x - lastx;
				test2 = y - lasty;
			}

			if (test1 < (test2 / (lasty - cury) * (lastx - curx))) {
				hits++;
			}
		}

		return ((hits & 1) != 0);
	}

	public PolygonThing(int x, int y) {
		super(x, y);
	}

	@Override
	public XMLElement startXmlization() {
		XMLElement xmlElement2 = super.startXmlization();
		XMLElement xmlVertexx = new XMLElement();
		xmlVertexx.setName("Points");
		xmlVertexx.setAttribute("count", "" + vertex.size());
		for (int index = 0; index < vertex.size(); index++) {
			XMLElement vertexXml = new XMLElement();
			Point point = vertex.get(index);
			vertexXml.setName("point-" + index);
			vertexXml.setAttribute("x", "" + point.x);
			vertexXml.setAttribute("y", "" + point.y);
			vertexXml.setAttribute("first", "" + point.first);
			xmlVertexx.addChild(vertexXml);
		}
		xmlElement2.addChild(xmlVertexx);
		return xmlElement2;
	}

	public PolygonThing startDesXmlization(XMLElement father) {
		Thing thing = super.startDesXmlization(father);

		PolygonThing polygonThing = (PolygonThing) thing;

		XMLElement pointsElement = father.getChild("Points");
		boolean firstReaded = false;
		for (int index = 0; index < pointsElement.getChildCount(); index++) {
			XMLElement pointElement = pointsElement.getChild(index);
			if (pointElement.getName().startsWith("point-")) {

				String stringX = pointElement.getAttribute("x");
				int x = 0;
				if (stringX != null)
					x = Integer.parseInt(stringX);

				String stringY = pointElement.getAttribute("y");
				int y = 0;
				if (stringY != null)
					y = Integer.parseInt(stringY);

				String stringFirst = pointElement.getAttribute("first");
				boolean first = false;
				if (stringY != null)
					first = Boolean.parseBoolean(stringFirst);

				boolean insert = false;

				if (first) {
					if (!firstReaded) {
						insert = true;
						firstReaded = true;
					}
				} else {
					insert = true;
				}

				if (insert) {
					Point point = new Point(x, y);
					point.first = first;
					polygonThing.addPoint(point);
				}

			} else {
				System.out
						.println("error leyendo el xml, se esperaba otro nombre");
			}
		}

		return polygonThing;

	}

	@Override
	protected Thing newElement() {
		return new PolygonThing();
	}

	public void refresh() {
		//no hacemos nada
	}
	
	@Override
	public Thing copy() {
		return copy(new PolygonThing());
	}
	
	protected Thing copy(PolygonThing thing) {

		List<Point> points = copyPoints(vertex);
		thing.vertex.addAll(points);
		thing.vertex.add(points.get(0));
		thing.setXY(points.get(0).x, points.get(0).y);
		return thing;
	}

	public List<Point> copyPoints(List<Point> points) {
		List<Point> news = new ArrayList<Point>();
		for (int i = 0; i < points.size() - 1; i++) {
			Point point = points.get(i);
			Point point2 = point.copyPoint();
			news.add(point2);
		}
		return news;
	}
}
